import {
  PerspectiveCamera,
  Scene,
  SpriteMaterial,
  WebGLRenderer,
  SphereGeometry,
  MeshBasicMaterial,
  PointLight,
  TextureLoader,
  Sprite,
  Vector3,
  Color,
  NormalBlending,
  ShaderMaterial,
  CanvasTexture,
  Mesh,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
import {
  CSS3DRenderer,
  CSS3DObject,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";

import Data from "./data";
const earthImg = `https://idres0.gzbohu.com/u/staff_idcard/20250615/2d946a52-816e-4e8a-94f0-2ca3e6acf930.jpg`;

// 创建相机
export function createCamera() {
  const camera = new PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  camera.position.z = 5;
  return camera;
}

// 创建控制器
export function createControls(
  camera: PerspectiveCamera,
  canvas: HTMLCanvasElement
) {
  const controls = new OrbitControls(camera, canvas);
  controls.enableDamping = true;
  controls.update();
  controls.minDistance = 3; // 设置最小缩放距离
  controls.maxDistance = 10; // 设置最大缩放距离
  return controls;
}

// 创建渲染器
export function createRenderer(canvas: HTMLCanvasElement) {
  const renderer = new WebGLRenderer({ canvas, antialias: true, alpha: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  return renderer;
}

// html渲染
export function createCSSRenderer(container: HTMLElement) {
  const css3dRenderer = new CSS3DRenderer();
  css3dRenderer.setSize(window.innerWidth, window.innerHeight);
  css3dRenderer.domElement.style.position = "absolute";
  css3dRenderer.domElement.style.top = "0";
  css3dRenderer.domElement.style.left = "0";
  document.body.appendChild(css3dRenderer.domElement);

  return css3dRenderer;
}

function createdCSS2DRenderer(container: HTMLElement) {
  const labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.domElement.style.position = "absolute";
  labelRenderer.domElement.style.top = "0";
  labelRenderer.domElement.style.pointerEvents = "none";
  document.body.appendChild(labelRenderer.domElement);
  return labelRenderer;
}

export class World {
  protected readonly camera: PerspectiveCamera;
  protected readonly scene: Scene;
  protected readonly controls: OrbitControls;
  protected readonly renderer: WebGLRenderer;
  protected readonly particleCount: number;
  protected globeMesh: any;
  protected labelRenderer: any;

  constructor(protected canvas: HTMLCanvasElement) {
    // 1创建场景
    this.scene = new Scene();
    // 创建渲染器
    this.renderer = createRenderer(this.canvas);
    // 创建相机
    this.camera = createCamera();
    // 创建控制器
    this.controls = createControls(this.camera, this.canvas);
    this.particleCount = 80;
    this.labelRenderer = createdCSS2DRenderer(this.canvas);
  }

  render() {
    this.renderer.render(this.scene, this.camera);
  }
  updateSatellitePosition() {
    this.scene.traverse((object) => {
      if (object instanceof CSS2DObject) {
        const direction = object.position
          .clone()
          .sub(this.camera.position)
          .normalize();
        const globeCenter = new Vector3(0, 0, 0); // 地球中心
        const globeDirection = object.position
          .clone()
          .sub(globeCenter)
          .normalize();
        const dotProduct = direction.dot(globeDirection);

        // 如果点积小于零，则标签在地球背面
        object.visible = dotProduct <  0.1;

        // 动态调整标签的缩放
        const distance = object.position.distanceTo(this.camera.position);
        const scale = Math.min(Math.max(0.1, 1000 / distance), 1);
        object.scale.set(scale, scale, scale);
      }
    });
  }

  animate() {
    requestAnimationFrame(() => this.animate());
    // 始终Y旋转 拖动后恢复
    this.globeMesh.rotation.y += 0.001;
    this.controls.update();
    this.updateSatellitePosition();

    this.labelRenderer.render(this.scene, this.camera);
    this.render();
  }

  init() {
    const R = 2.2; // 地区半径
    // 添加物体  --- 在将物体添加到网格
    const globeGeometry = new SphereGeometry(2, 100, 100); // 创建几何球体
    // 添加纹理材质
    const textureLoader = new TextureLoader();

    const earthTexture = textureLoader.load(earthImg); // bg
    const guangqun = textureLoader.load(
      `https://idres0.gzbohu.com/u/staff_idcard/20250615/a4cf801c-ee9d-4356-8cbd-90153159d5eb.png`
    );
    const globeMaterial = new MeshBasicMaterial({
      map: earthTexture, // 使用加载的纹理
    });
    this.globeMesh = new Mesh(globeGeometry, globeMaterial);
    // 创建辉光
    // 创建精灵材质对象SpriteMaterial
    const spriteMaterial = new SpriteMaterial({
      map: guangqun, // 设置精灵纹理贴图
      color: 0x4390d1,
      transparent: true, //开启透明
      opacity: 0.3, // 可以通过透明度整体调节光圈
      depthWrite: false, //禁止写入深度缓冲区数据
    });

    // 创建表示地球光圈的精灵模型
    const sprite = new Sprite(spriteMaterial);
    sprite.scale.set(R * 3.0, R * 3.0, 1); //适当缩放精灵
    this.scene.add(sprite);
    this.createEarthAperture(R);
    this.createMarkupPoint(R);
    this.scene.add(this.globeMesh);
    // 添加点光源
    const pointLight = new PointLight(0xffffff);
    pointLight.position.set(5, 5, 5);
    this.scene.add(pointLight);
    // 窗口大小变化时调整
    window.addEventListener("resize", () => {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    });
    this.animate();
  }

  createEarthAperture(radius: number) {
    const vertexShader = [
      "varying vec3	vVertexWorldPosition;",
      "varying vec3	vVertexNormal;",
      "varying vec4	vFragColor;",
      "void main(){",
      "	vVertexNormal	= normalize(normalMatrix * normal);", //将法线转换到视图坐标系中
      "	vVertexWorldPosition	= (modelMatrix * vec4(position, 1.0)).xyz;", //将顶点转换到世界坐标系中
      "	// set gl_Position",
      "	gl_Position	= projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
      "}",
    ].join("\n");

    //大气层效果
    const AeroSphere = {
      uniforms: {
        coeficient: {
          type: "f",
          value: 1.0,
        },
        power: {
          type: "f",
          value: 3,
        },
        glowColor: {
          type: "c",
          value: new Color(0x4390d1),
        },
      },
      vertexShader: vertexShader,
      fragmentShader: [
        "uniform vec3	glowColor;",
        "uniform float	coeficient;",
        "uniform float	power;",

        "varying vec3	vVertexNormal;",
        "varying vec3	vVertexWorldPosition;",

        "varying vec4	vFragColor;",

        "void main(){",
        "	vec3 worldCameraToVertex = vVertexWorldPosition - cameraPosition;", //世界坐标系中从相机位置到顶点位置的距离
        "	vec3 viewCameraToVertex	= (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;", //视图坐标系中从相机位置到顶点位置的距离
        "	viewCameraToVertex= normalize(viewCameraToVertex);", //规一化
        "	float intensity	= pow(coeficient + dot(vVertexNormal, viewCameraToVertex), power);",
        "	gl_FragColor = vec4(glowColor, intensity);",
        "}",
      ].join("\n"),
    };
    //球体 辉光 大气层
    const material1 = new ShaderMaterial({
      uniforms: AeroSphere.uniforms,
      vertexShader: AeroSphere.vertexShader,
      fragmentShader: AeroSphere.fragmentShader,
      blending: NormalBlending,
      transparent: true,
      depthWrite: false,
    });
    const sphere = new SphereGeometry(radius + 0, 50, 50);
    const mesh = new Mesh(sphere, material1);
    this.scene.add(mesh);
  }

  latLongToVector3(lat: number, lon: number, radius: number) {
    const phi = (90 - lat) * (Math.PI / 180);
    const theta = (lon + 180) * (Math.PI / 180);

    const x = -radius * Math.sin(phi) * Math.cos(theta);
    const y = radius * Math.cos(phi);
    const z = radius * Math.sin(phi) * Math.sin(theta);

    return new Vector3(x, y, z);
  }

  cteatedText(text: string, color: any, position: any) {
    const el = document.createElement("div");
    el.className = "label";
    el.style.color = color;
    el.textContent = text;
    el.style.fontSize = "13px";
    // 添加点击事件监听器
    el.onclick = () => {
      console.log("点击了标签");
    };
    const cssObject = new CSS2DObject(el);
    cssObject.position.copy(position);
    return cssObject;
  }

  pointCircle(position: any) {
    const markerGeometry = new SphereGeometry(0.01, 4, 4);
    const markerMaterial = new MeshBasicMaterial({ color: 0x95cefc });
    const marker = new Mesh(markerGeometry, markerMaterial);
    marker.position.copy(position);
    return marker;
  }

  createMarkupPoint(R: number) {
    Data.forEach((item: any) => {
      const position: any = this.latLongToVector3(
        item.latitude + 1,
        item.longitude - 0.5,
        2
      );
      this.globeMesh.add(this.pointCircle(position));
      // 帮我完善文本标签添加可点击事件 cteatedText
      const textObject = this.cteatedText(item.city, "#ffffff", position);
      this.globeMesh.add(textObject);
    });
  }

  start() {
    this.init();
  }
}
